/**
 * buffer pointer and list
 */

#include "sysbuf.h"

static uint32_t g_buf_id;
static slists_group_t g_sys_buf_group[SYSBUF_GROUP_COUNT];
static sysbuf_t g_sys_buf[SYS_BUF_MAX_COUNT];

/**
 * sysbuf_init
 */
void sysbuf_init(void)
{
    int i;
    psysbuf_t buf;
    pslists_t psl;

    g_buf_id = 0;

    for (i=0; i<SYSBUF_GROUP_COUNT; i++) {
        slists_group_init(&g_sys_buf_group[i]);
    }

    memset(g_sys_buf, 0, sizeof(g_sys_buf));

    for (i=0; i<SYS_BUF_MAX_COUNT; i++)
    {
        buf = &g_sys_buf[i];
        buf->mark = SYS_BUF_MARK;
        psl = &(buf->list);
        INIT_LIST_HEAD(&(psl->node));
        psl->group = &(g_sys_buf_group[SYSBUF_GROUP_FREE]);
        slists_free(psl);
    }
}

/**
 * sysbuf_group_set
 */
int sysbuf_group_reset(sysbuf_group_t *gd, int group)
{
    int i;
    psysbuf_t buf, oldbuf;
    pslists_group_t psg;
    pslists_t psl;

    if (!gd || group <= SYSBUF_GROUP_FREE
            || group >= SYSBUF_GROUP_COUNT ) {
        return -EPERM;
    }

    psg = &(g_sys_buf_group[group]);

    /* clear spool */
    for (i=0; i<SYS_BUF_MAX_COUNT; i++)
    {
        buf = &g_sys_buf[i];
        psl = &(buf->list);
        if (psl->group == psg) {
            psl->group = &(g_sys_buf_group[SYSBUF_GROUP_FREE]);
            slists_free(psl);
        }
    }

    /* reset group */
    slists_group_deinit(psg);
    slists_group_init(psg);

    /* init buffer */
    oldbuf = NULL;
    for(i=0; i<gd->count; i++)
    {
        psl = slists_alloc(&(g_sys_buf_group[SYSBUF_GROUP_FREE]));
        if (!psl) {
            return -ENOMEM;
        }

        buf = container_of(psl, sysbuf_t, list);

        buf->flags = 0;
        buf->offset = 0;
        buf->size = 0;
        buf->maxsize = gd->unitsize;
        if (!oldbuf) {
            buf->vaddr = gd->vaddr;
            buf->haddr = gd->haddr;
        } else {
            buf->vaddr = oldbuf->vaddr + gd->unitsize;
            buf->haddr = oldbuf->haddr + gd->unitsize;
        }
        oldbuf = buf;

        psl->group = psg;
        slists_free(psl);
    }

    return 0;
}

/**
 *  sysbuf_free
 */
int sysbuf_free(psysbuf_t buf)
{
    int res;
    if ( !buf )
        return -EPERM;

    res = slists_free(&(buf->list));

    return res;
}

/**
 *  sysbuf_alloc
 */
psysbuf_t sysbuf_alloc(int group)
{
    psysbuf_t buf;
    pslists_t psl;
    pslists_group_t psg;

    if (group <= SYSBUF_GROUP_FREE
            || group >= SYSBUF_GROUP_COUNT ) {
        return NULL;
    }

    psg = &(g_sys_buf_group[group]);
    psl = slists_alloc(psg);
    if (!psl) {
        return NULL;
    }

    buf = container_of(psl, sysbuf_t, list);

    buf->flags = 0;
    buf->offset = 0;
    buf->size = 0;
    g_buf_id++;
    if (g_buf_id == 0)
        g_buf_id = 1;
    buf->buffid = g_buf_id;

    return buf;
}


void sysbuf_reset(int group)
{
	sysbuf_group_t gp;

	switch (group)
	{
	case SYSBUF_GROUP_MSGBUFS:
	{
		gp.type = SYSBUF_GROUPTYPE_SRAM;
		gp.vaddr = 0;
		gp.haddr = (phys_addr_t)malloc(MSGBUF_MAX_BUF_CNT * MSGBUF_MAX_BUF_LEN);
		gp.count = MSGBUF_MAX_BUF_CNT;
		gp.unitsize = MSGBUF_MAX_BUF_LEN;
	}break;
	case SYSBUF_GROUP_DATBUFS:
	{
		gp.type = SYSBUF_GROUPTYPE_DDR;
		gp.vaddr = (phys_addr_t)malloc(DATBUF_MAX_BUF_CNT * DATBUF_MAX_BUF_LEN + 16);
		gp.haddr = (phys_addr_t)gp.vaddr;
		gp.count = DATBUF_MAX_BUF_CNT;
		gp.unitsize = DATBUF_MAX_BUF_LEN;
	}break;
	default:
		return;
	};

	sysbuf_group_reset(&gp, group);
}
